package util

import "sync"

type node struct {
	value interface{}
	next  *node
}

type LinkedQueue struct {
	head *node
	tail *node
	size int

	sync.RWMutex
}

func (queue *LinkedQueue) Size() int {
	return queue.size
}

func (queue *LinkedQueue) Peek() interface{} {
	queue.RLock()
	defer queue.RUnlock()
	if queue.head == nil || queue.size == 0 {
		return nil
	}
	return queue.head.value
}

func (queue *LinkedQueue) Add(value interface{}) {
	queue.Lock()
	defer queue.Unlock()

	new_node := &node{
		value: value,
		next:  queue.tail,
	}
	if queue.tail == nil {
		queue.head = new_node
		queue.tail = new_node
	} else {
		queue.tail.next = new_node
		queue.tail = new_node
	}
	queue.size++
	new_node = nil
}

func (queue *LinkedQueue) Get() interface{} {
	queue.Lock()
	defer queue.Unlock()

	if queue.head == nil || queue.size == 0 {
		return nil
	}
	first_node := queue.head
	res := first_node.value
	queue.head = first_node.next
	first_node.next = nil
	first_node.value = nil
	queue.size--
	if queue.size == 0 {
		queue.tail = nil
	}
	first_node = nil
	return res
}
